#!/usr/bin/python

'''
Parser for game files into more usable replay files in custom format, below.
Authors:
    Stuart Davis
    Shengling Hu
    Bennett Wineholt

Usage:
    From containing directory
    python parser.py

    or

    python parser.py -g 111280
'''

import json
import pprint
import os
import sys
import pickle
from urllib2 import Request, urlopen, URLError, HTTPError
import gzip
from StringIO import StringIO

from optparse import OptionParser

GAMES_PREFIX = os.path.join('..', '..', 'data', 'games')
if (not os.path.isdir(GAMES_PREFIX)):
    os.mkdir(GAMES_PREFIX)
REPLAY_PREFIX = os.path.join('..', '..', 'data', 'replays')
if (not os.path.isdir(REPLAY_PREFIX)):
    os.mkdir(REPLAY_PREFIX)
DEFAULT_GAME_NO = '115671'
DEFAULT_GAME = os.path.join(GAMES_PREFIX, DEFAULT_GAME_NO)
DEFAULT_REPLAY = os.path.join(REPLAY_PREFIX, DEFAULT_GAME_NO)

MAXROW = 128
MAXCOL = 112


'''
Each entry in available game file is an ant.
<row> <col> <start turn> <end turn> <player> <moves>
[12,28,110,186,5,"nw-------n-ns-nsnwsesnns-sn-nswssssnsenwewe-w-n--w-e--we-w-ee------w---ewn-n"]

<row> <col> <player> <turn destroyed>
[132,7,0,151]
'''

'''
Parser
'''
def decodeReplay(json_replay):
    '''
    returns an array of ants indexed by player and turn number
    state[2][5] returns a list of [row,col] ant locations of player 2 at turn 5
    state[2][5] is an empty list if there are no ants for player 2 at turn 5
    '''
    #
    data = json.loads(json_replay)
    statuses = data["status"]
    cutoffs = data["replaydata"]["cutoff"]
    food = data["replaydata"]["food"]
    ants = data["replaydata"]["ants"]
    hills = data["replaydata"]["hills"]
    turns = data["playerturns"]
    scores = data["score"]

    winner = scores.index(max(scores))

    maxTurn = max(turns) + 1 #one extra turn is used
    #create an ant state array for each player
    state = []
    out_hills = []
    for hill in hills:
        temp = [[] for i in range(maxTurn)]
        state.append(temp)
        (row, col, player, endTurn) = tuple(hill)
        out_hills.insert(player,[row,col])

    for ant in ants:
        (row, col, startTurn, endTurn, player, moves) = tuple(ant)

        state[player][startTurn].append([row,col])
        moveIndex = 0
        for i in range(startTurn+1,endTurn):
            row,col = state[player][i-1][-1] # finds the last ant on the previous turn
            move = moves[moveIndex]
            if move == 'n':
                row -= 1
            elif move == 's':
                row += 1
            elif move == 'w':
                col -= 1
            elif move == 'e':
                col += 1

	    #account for wraparound
	    if row < 0:
	    	row += MAXROW
	    elif row >= MAXROW:
	    	row -= MAXROW

	    if col < 0:
	    	col += MAXCOL
	    elif col >= MAXCOL:
	    	col -= MAXCOL

            state[player][i].append([row,col])
            moveIndex += 1

    return ([winner], out_hills,state)

def pullReplayData(gameID):
    replay = ""
    url = "http://aichallenge.org/game/%s" % gameID
    req = Request(url)
    req.add_header('Content-Type', 'application/json')
    req.add_header('Accept-Encoding', 'gzip, deflate')
    #req.add_header('Content-type', 'application/json')
    try:
        response = urlopen(req)
        buf = StringIO(response.read())
        f = gzip.GzipFile(fileobj=buf)
        replay = f.read()
        response.close()
    except HTTPError, e:
        print e.code
        print e.read()
    return replay

def getRank(jsonReplay, playerID):
    """
    returns an integer representing 1st, 2nd, etc... among the player scores
    for player playerID
    """
    data = json.loads(jsonReplay)
    scores = data["score"]
    playerScore = scores[playerID]
    scores.sort(reverse=True)
    return scores.index(playerScore)+1

def getScore(jsonReplay, playerID):
    """
    returns the score for player playerID
    """
    data = json.loads(jsonReplay)
    scores = data["score"]
    return scores[playerID]

def HandleOptions():
    parser = OptionParser()
    parser.add_option("-g", action="store", type="string", dest="game_no",
                      default="",
                      help="Game number to parse")
    (options, args) = parser.parse_args()
    return (options, args)


'''
Pull and parse one game specified by gameId.
'''
def parseGame(game):
    print('Parsing game ' + str(game) + '\n')
    replayData = pullReplayData(game)
    output_filename = os.path.join(REPLAY_PREFIX,str(game))
    out_file = open(output_filename, 'wb')
    pickle.dump(decodeReplay(replayData), out_file)
    print('Done with ' +  str(game) + '\n')
    out_file.close()


'''
Pull, save, and parse one game specified by gameId.
'''
def parseSaveGame(game):
    print('Pulling game ' + str(game) + '\n')
    replayData = pullReplayData(game)
    print('Saving game ' + str(game) + '\n')
    json_outname = os.path.join(GAMES_PREFIX, str(game))
    json_out = open(json_outname, 'wb')
    json_out.write(replayData)
    json_out.close()
    output_filename = os.path.join(REPLAY_PREFIX,str(game))
    out_file = open(output_filename, 'wb')
    print('Parsing game ' + str(game) + '\n')
    pickle.dump(decodeReplay(replayData), out_file)
    print('Done with ' +  str(game) + '\n')
    out_file.close()


'''
Run the parser on a single input file.
'''
def main(options):
    """ Code for reading from file, not in use right now
    to_parse = DEFAULT_GAME
    output_filename = DEFAULT_REPLAY
    if (options.game_no != ''):
        to_parse = os.path.join(GAMES_PREFIX, options.game_no)
        output_filename = os.path.join(REPLAY_PREFIX, options.game_no)

    try:
        in_file = open(to_parse, 'r')
        json_data = in_file.read()
    except IOError:
        print('Could not open game ' + to_parse + '\n' )

    print('Parsing game ' + to_parse + '\n')
    state = decodeReplay(json_data)
    in_file.close()
    out_file = open(output_filename, 'wb')
    pickle.dump(state,out_file)
    print('Done')

    """
    games = [115671]#, 116944, 117034, 117067, 117297, 149452, 149357, 149342, 149316, 149186, 149166, 147481]
    for game in games:
        parseGame(game)


if __name__ == '__main__':
    (options, args) = HandleOptions()
    main(options)

